package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.MyGreenImageScan;
import com.heima.common.aliyun.MyGreenTextScan;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.exception.CustomException;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsContentDto;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.stream.Collectors;


@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private MyGreenTextScan myGreenTextScan;

    @Autowired
    private MyGreenImageScan myGreenImageScan;

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private IArticleClient iArticleClient;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;


    class ContentData{
        private String text;
        private List<String> urls;

        public String getText() {
            return text;
        }

        public void setText(String text) {
            this.text = text;
        }

        public List<String> getUrls() {
            return urls;
        }

        public void setUrls(List<String> urls) {
            this.urls = urls;
        }
    }

    //提取文本和图片信息
    private ContentData getContentData(WmNews wmNews){
        ContentData contentData = new ContentData();

        String content = wmNews.getContent();
        HashSet<String> urls = new HashSet<>();
        StringBuilder sb = new StringBuilder();

        List<WmNewsContentDto> wmNewsContentDtos = JSONArray.parseArray(content, WmNewsContentDto.class);
        for (WmNewsContentDto dto : wmNewsContentDtos) {
            if(Objects.equals(dto.getType(), WemediaConstants.WM_NEWS_TYPE_IMAGE)){
                urls.add(dto.getValue());
            }else if(Objects.equals(dto.getType(),WemediaConstants.WM_NEWS_TYPE_TEXT)){
                sb.append(dto.getValue());
                sb.append("-");
            }
        }
        //把标题加入
        sb.append(wmNews.getTitle());

        //封面中的图片也审核
        String images = wmNews.getImages();
        if(StringUtils.isNotBlank(images)){
            String[] split = images.split(",");
            urls.addAll(Arrays.asList(split));
        }
        contentData.setText(sb.toString());
        contentData.setUrls(new ArrayList<>(urls));

        return contentData;
    }

    @PostConstruct
    public void initSensitives(){
        //从数据库中查询敏感词
        List<String> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery()
                        .select(WmSensitive::getSensitives))
                .stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        SensitiveWordUtil.initMap(wmSensitives);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Async
    public void autoScan(WmNews wmNews) {
        //判断当前文章待审核状态
        if(!Objects.equals(wmNews.getStatus(),WmNews.Status.SUBMIT.getCode())){
            return;
        }
        ContentData contentData = getContentData(wmNews);

        //敏感词审核
        String text = contentData.getText();
        Map<String, Integer> result = SensitiveWordUtil.matchWords(text);
        if(!result.isEmpty()){
            saveWmNewsStatus(wmNews,WmNews.Status.FAIL,"内容包含敏感词");
            return;
        }

        //文章内容审核
        boolean b = autoScanText(contentData.getText(), wmNews);
        if(!b){
            //审核失败,直接结束
            return;
        }

        //图片审核
        b = autoScanImage(contentData.getUrls(), wmNews);
        if(!b){
            //审核失败,直接结束
            return;
        }

        //通过远程接口保存数据
        ResponseResult responseResult = saveAppArticle(wmNews);

        if(responseResult == null || !Objects.equals(responseResult.getCode(),AppHttpCodeEnum.SUCCESS.getCode())){
            //远程接口处理失败
            throw new CustomException(AppHttpCodeEnum.SERVER_ERROR,"调用远程接口失败");
        }

        Long articleId =(Long) responseResult.getData();

        //执行本地保存
        wmNews.setArticleId(articleId);
        saveWmNewsStatus(wmNews,WmNews.Status.PUBLISHED,"审核通过");
    }

    private ResponseResult saveAppArticle(WmNews wmNews) {
        //wmNews 转成参数对象
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,articleDto);

        Long articleId = wmNews.getArticleId();
        if(articleId != null){
            articleDto.setId(articleId);
        }

        articleDto.setAuthorId(Long.valueOf(wmNews.getUserId()));
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if(wmNews == null){
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST,"用户不存在"+wmNews.getUserId());
        }
        articleDto.setAuthorName(wmUser.getName());

        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if(wmChannel == null){
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST,"频道不存在"+wmNews.getChannelId());
        }
        articleDto.setChannelName(wmChannel.getName());

        ResponseResult responseResult = iArticleClient.saveArticle(articleDto);
        return responseResult;
    }

    private boolean autoScanText(String text, WmNews wmNews) {
        try {
            Map map = myGreenTextScan.greenTextScanStrongVersion(text);

            String suggestion = (String) map.get("suggestion");

            if(Objects.equals(suggestion,"pass")){
                //成功
                return true;
            }else if(Objects.equals(suggestion,"block")){
                //失败 状态为2
                saveWmNewsStatus(wmNews,WmNews.Status.FAIL,"文章内容包含敏感词,请重新确认");
                return false;
            }else if(Objects.equals(suggestion,"review")){
                //转人工 状态为3
                saveWmNewsStatus(wmNews,WmNews.Status.ADMIN_AUTH,"文章内容可能包含敏感词,需要人工处理");
                return false;
            }

        } catch (Exception e) {
            log.error("调用阿里云审核接口失败",e);
        }
        saveWmNewsStatus(wmNews,WmNews.Status.ADMIN_AUTH,"文章内容可能包含敏感词,需要人工处理");
        return false;
    }

    private boolean autoScanImage(List<String> urls, WmNews wmNews) {
        if(CollectionUtils.isEmpty(urls)){
            // 没有数据 代表不需要审核
            return true;
        }
        try {
            String tempFileUrl =null;
            for (String url : urls) {
                byte[] bytes1 = fileStorageService.downLoadFile(url);
                String fileExtension = url.substring(url.lastIndexOf("."));
                System.out.println(fileExtension);
                Path tempFilePath = Files.createTempFile("temp", fileExtension);
                System.out.println(tempFilePath);
                Files.write(tempFilePath,bytes1, StandardOpenOption.CREATE);
                tempFileUrl = tempFilePath.toString();
            }


            Map map = myGreenImageScan.imageScanStrongLocalVersion(tempFileUrl);

            String suggestion = (String) map.get("suggestion");

            if(Objects.equals(suggestion,"pass")){
                //成功
                return true;
            }else if(Objects.equals(suggestion,"block")){
                //失败 状态为2
                saveWmNewsStatus(wmNews,WmNews.Status.FAIL,"文章图片包含敏感词,请重新确认");
                return false;
            }else if(Objects.equals(suggestion,"review")){
                //转人工 状态为3
                saveWmNewsStatus(wmNews,WmNews.Status.ADMIN_AUTH,"文章图片可能包含敏感词,需要人工处理");
                return false;
            }

        } catch (Exception e) {
            log.error("调用阿里云审核接口失败",e);
        }
        saveWmNewsStatus(wmNews,WmNews.Status.ADMIN_AUTH,"文章图片可能包含敏感词,需要人工处理");
        return false;
    }

    private void saveWmNewsStatus(WmNews wmNews,WmNews.Status fail,String reason){
        wmNews.setStatus(fail.getCode());
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }
}

